/**
  ******************************************************************************
  * @file 	zbProtocol.h 
  * @brief  Protocol header file 
  ******************************************************************************
  

Name					Size (bytes)	Description
Start of packet / ID	1			0x01 (SOH) default
Transaction Number		1			repeats master
Command					1			See command bytes and their arguments below
Flags					1			Flags to show status of packet, see below definition
Size					2			MSB first size of packet payload 
Payload					Variable	Payload or command arguments
CRC						2			MSB? first CRC of entire packet, including header
*/
#include "zbProtocol.h"

// file scope
u16 g_respBytes = 0;
//volatile u32	CRCValue = 0;
//


// file scope rx header vars
u8 txn, cmd, flags = 0;
u16 payloadsize = 0x00;
u32 CRCVal = 0x00;

u8 checkPacket(u8 packet[], u16 packetSize)
{
	u16 i = 0;
	// check to find header before end of packet
	for(i=0; i<packetSize; i++)
	{
		if(packet[i] == ID)
		{
			// check txn number, todo
			txn = packet[++i];
			// check the command 
			cmd = packet[++i];
			// if the command is not within our current commands
			if(cmd > 10) 
			{
				continue;
			}
			flags = packet[++i];
			payloadsize = bytesToU16(&packet[++i]);i++; 
			// check to see if size is greater than
			if(payloadsize > packetSize + hdrSize)
			{
				// if the packet says the size is bigger than the
				// max allowed payload we must have garbage, keep looking
				if(payloadsize > maxPayloadSize)
				{
					continue;
				}
				// todo return incomplete packet
				return 0x01;
			}
			// skip to crc
			i += payloadsize;
			CRCVal = bytesToU32(&packet[++i]);
			// check crc
			CRC_ResetDR();
			if(CRCVal != CRC_CalcBlockCRC((uint32_t *)packet, (payloadsize + hdrSize)/4))
			{
				// todo return invalid crc
			}
			
			return 0x00; // no error 
		}
	}
	printf("Packet Info txn: %i size: %i crc: %lX i: %i", txn, payloadsize, CRCVal, i);
	return 0xFF; // no valid data 
}

u16 processPacket(u8 packet[], u16 packetSize)
{
	u16 respSize = 0, offset = 0, payloadSize = 0, i=0;
	// update header info and ensure packet ok	
	if(checkPacket(packet, packetSize) != 0) return respSize;

	switch(cmd)
	{
		// read returns x bytes from the glbVars
		case cmd_read: 
			// get offset from inc packet
			offset = bytesToU16(&packet[hdrSize]);
			// get size from inc packet
			payloadSize = bytesToU16(&packet[hdrSize + 2]);
			// check to be sure we dont do too much ! 
			if(offset+payloadSize > g_VarsSize)
			{
				// just return nothing, set error
				respSize = createResponse(g_PktTXBuff, 0x00, 0x01);
				break;
			}
			// move the bytes into the txbuffer
			for(i=0; i<payloadSize; i++)
			{
				g_PktTXBuff[hdrSize+i] = g_Vars[offset+i];
			}
			 
			// create response of 4 byte status
			respSize = createResponse(g_PktTXBuff, payloadSize, 0x00);		

		case cmd_write: // get or set the current second ticks  05
			// write will write the data over the current data 
			// todo
			break;
			

		default:
			break; // no response

	}

	return respSize;
}

u16 createResponse(u8 packet[], u16 payloadSize, u8 flags)
{
	int pad,j = 0; // offset to payload

	// put a header on it 
	createHeader(packet, txn, cmd, flags, payloadSize);
	// append padding
	pad = ((4 - ((hdrSize+payloadSize)%4)) & !4);
	for(j=0; j<pad; j++)
	{
		g_PktTXBuff[hdrSize+payloadSize+j] = pad;
	}
	// append crc
	appendCRC(packet, payloadSize+hdrSize+pad); // crc the payload and header
	// return whole size of packet
	return hdrSize+payloadSize+pad+crcSize;
}

void putPacketInBuffer(u8 payload[], u8 TXN, u8 command, u8 flags, u16 size)
{
	// counter
	u16 i,j,sop;
	j = 0;
	sop = (1024 + hdrSize) * PktBuf; // double buffer

	// stick it in after the header offset
	for(i = sop + hdrSize; i < size; i++)
	{
		//g_PktBuff[i] = payload[j];
		 j++;
	}

	// pre pend header, make the size in packet the total size of packet
	//createHeader(&g_PktBuff[sop], TXN, command, flags, size + hdrSize + 2);

	// append crc, size is all but last 2 bytes, we cant crc the place where crc would be
	//appendCRC(&g_PktBuff[sop], size + hdrSize);

}

 /**
  * @brief  Creates header at specified location     
  * @note   		
  * @param  location to put header, command of packet, flags
  * @retval bytes in header
  */
u8 createHeader(u8 headerLocation[], u8 TXN, u8 command, u8 flags, u16 payloadSize )
{
	// variables used 
	u8 i;
	
	// fill out vars
	i 		= 0;

	// put in memory as desired
	headerLocation[i++] = 	ID;
	headerLocation[i++] =	TXN;
	headerLocation[i++] =	command;
	headerLocation[i++] =	flags;
	headerLocation[i++] = 	(u8)((payloadSize>>8) & 0xFF);
	headerLocation[i++] =	(u8)(payloadSize & 0xFF);

	return i;
}

 /**
  * @brief  calculates the crc32 for the entire buffer passed in, and puts it just after it    
  * @note   		
  * @param 	databuffer is the packet to get the crc 4, size is the size of said buffer
  * @retval 
  */
void appendCRC(u8 dataBuffer[], u16 sizeBytes)
{
	u32 CRCVal = 0;
	u16 sizeWords = sizeBytes/4;
	CRC_ResetDR();
	CRCVal = CRC_CalcBlockCRC((uint32_t *)dataBuffer, sizeWords);
	u32ToBytes(CRCVal, &dataBuffer[sizeBytes]);
}

void u32ToBytes(u32 value, u8 buffer[])
{
	buffer[0] 	=   (u8)((value>>24) & 0xFF);
    buffer[1] 	=   (u8)((value>>16) & 0xFF);
	buffer[2] 	= 	(u8)((value>>8) & 0xFF);
	buffer[3] 	=	(u8)(value & 0xFF);
}

u32 bytesToU32(u8 buffer[])
{
	u32 retU32 = 0;
	u16 high = 0, low = 0;
	high = (((u16)buffer[0])<<8) | buffer[1];
	low = (((u16)buffer[2])<<8) | buffer[3];
	retU32 = (((u32)high)<<16) | low;

	return retU32;
}

u16 bytesToU16(u8 buffer[])
{
	u16 retU16 = 0;
	retU16 = (((u16)buffer[0])<<8) | buffer[1];

	return retU16;
}
